package com.ddone.filter;

import com.ddone.helper.JwtHelper;
import com.ddone.model.vo.LoginVo;
import com.ddone.model.vo.Result;
import com.ddone.security.AuthUser;
import com.ddone.service.SysLoginLogService;
import com.ddone.util.IpUtil;
import com.ddone.util.ResponseUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ddone
 * @date 2024/3/31-20:50
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private RedisTemplate<String, Object> redisTemplate;

    private SysLoginLogService sysLoginLogService;

    private LoginVo loginVo;

    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate<String, Object> redisTemplate, SysLoginLogService sysLoginLogService) {
        this.setAuthenticationManager(authenticationManager);
        //指定登录接口及提交方式，可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/index/login", "POST"));
        this.redisTemplate = redisTemplate;
        this.sysLoginLogService = sysLoginLogService;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            loginVo  = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 认证成功后执行
     *
     * @param request
     * @param response
     * @param chain
     * @param authResult
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
        AuthUser authUser = (AuthUser) authResult.getPrincipal();
        String token = JwtHelper.createToken(authUser.getSysUser().getId(), authUser.getSysUser().getUsername());
        Collection<GrantedAuthority> authorities = authUser.getAuthorities();
        String username = authUser.getUsername();
        // 登录成功 将权限保存到redis里面
        redisTemplate.boundValueOps(username).set(authUser);

        // 保存登录日志
        sysLoginLogService.recordLoginLog(username, IpUtil.getIpAddress(request),1,"登录成功");

        // 登录成功 将Token返回给前端
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        ResponseUtil.out(response, Result.ok(map));
    }

    /**
     * 认知失败后执行
     *
     * @param request
     * @param response
     * @param e
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) throws IOException, ServletException {
        sysLoginLogService.recordLoginLog(loginVo.getUsername(), IpUtil.getIpAddress(request),0,"登录失败");
        ResponseUtil.out(response, Result.build(null, 444, e.getMessage()));
    }
}
